/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package visitor;

import composite.Component;
import composite.boolean_expression.Cond;
import composite.boolean_expression.Factb;
import composite.boolean_expression.Termb;
import composite.boolean_expression.factb.FactbCond;
import composite.boolean_expression.factb.FactbNot;
import composite.boolean_expression.factb.factb_expr.RelopEq;
import composite.boolean_expression.factb.factb_expr.RelopGe;
import composite.boolean_expression.factb.factb_expr.RelopGt;
import composite.boolean_expression.factb.factb_expr.RelopLe;
import composite.boolean_expression.factb.factb_expr.RelopLt;
import composite.boolean_expression.factb.factb_expr.RelopNeq;
import composite.number_expression.Expr;
import composite.number_expression.Fact;
import composite.number_expression.Term;
import composite.number_expression.Termp;
import composite.number_expression.fact.FactExpr;
import composite.number_expression.fact.FactId;
import composite.number_expression.fact.FactNum;
import composite.number_expression.term.AddTerm;
import composite.number_expression.term.MinusTerm;
import composite.number_expression.termp.DivTermp;
import composite.number_expression.termp.MultTermp;
import composite.number_expression.termp.RemTermp;
import exception.SyntaxException;
import java.util.Iterator;

/**
 *
 * @author Antonio
 */
public class EvalutationCond implements Visitor {

    private int num;
    private boolean bool;

    public EvalutationCond() {

        num = 0;
        bool = false;
    }

    @Override
    public void visit(Cond cond) {

        if (cond.getState().size() == 1) {

            cond.getState().get(0).accept(this);
        } else {

            for (Component tb : cond.getState()) {

                tb.accept(this);

                if (bool) {// cond. cortocircuito OR

                    break;
                }
            }
        }
    }

    @Override
    public void visit(Termb termb) {

        if (termb.getState().size() == 1) {

            termb.getState().get(0).accept(this);
        } else {

            for (Component fb : termb.getState()) {

                fb.accept(this);

                if (!bool) {// cond. cortocircuito AND

                    break;
                }
            }
        }
    }

    @Override
    public void visit(FactbCond factbCond) {

        factbCond.getState().accept(this);
    }

    @Override
    public void visit(FactbNot factbNot) {

        factbNot.getState().accept(this);

        bool = !bool;
    }

    @Override
    public void visit(RelopEq relopEq) {

        int left = 0;
        int right = 0;

        relopEq.getleft().accept(this);
        left = num;

        relopEq.getRight().accept(this);
        right = num;

        if (left == right) {

            bool = true;
        } else {

            bool = false;
        }
    }

    @Override
    public void visit(RelopGe relopGe) {

        int left = 0;
        int right = 0;

        relopGe.getleft().accept(this);
        left = num;

        relopGe.getRight().accept(this);
        right = num;

        if (left >= right) {

            bool = true;
        } else {

            bool = false;
        }
    }

    @Override
    public void visit(RelopGt relopGt) {

        int left = 0;
        int right = 0;

        relopGt.getleft().accept(this);
        left = num;

        relopGt.getRight().accept(this);
        right = num;

        if (left > right) {

            bool = true;
        } else {

            bool = false;
        }
    }

    @Override
    public void visit(RelopLe relopLe) {

        int left = 0;
        int right = 0;

        relopLe.getleft().accept(this);
        left = num;

        relopLe.getRight().accept(this);
        right = num;

        if (left <= right) {

            bool = true;
        } else {

            bool = false;
        }
    }

    @Override
    public void visit(RelopLt relopLt) {

        int left = 0;
        int right = 0;

        relopLt.getleft().accept(this);
        left = num;

        relopLt.getRight().accept(this);
        right = num;

        if (left < right) {

            bool = true;
        } else {

            bool = false;
        }
    }

    @Override
    public void visit(RelopNeq relopNeq) {

        int left = 0;
        int right = 0;

        relopNeq.getleft().accept(this);
        left = num;

        relopNeq.getRight().accept(this);
        right = num;

        if (left != right) {

            bool = true;
        } else {

            bool = false;
        }
    }

    @Override
    public void visit(Expr expr) {

        int temp = 0;

        if (expr.getStato().size() == 1) {

            expr.getStato().get(0).accept(this);
        } else {

            for (Component te : expr.getStato()) {

                te.accept(this);

                if (te instanceof AddTerm) {

                    temp += num;
                } else if (te instanceof MinusTerm) {

                    temp -= num;
                } else {

                    temp = num;
                }
            }
            num = temp;
        }
    }

    @Override
    public void visit(Term term) {

        int temp = 0;

        if (term.getStato().size() == 1) {

            term.getStato().get(0).accept(this);
        } else {

            for (Component tp : term.getStato()) {

                tp.accept(this);

                if (tp instanceof MultTermp) {

                    temp *= num;
                } else if (tp instanceof DivTermp) {

                    if (num == 0) {

                        throw new SyntaxException("Divisione per 0 non consentita");
                    } else {

                        temp /= num;
                    }
                } else if (tp instanceof RemTermp) {

                    temp %= num;
                } else {

                    if (temp == 0) {

                        temp = num;
                    } else {

                        throw new SyntaxException();
                    }
                }
            }
            num = temp;
        }
    }

    @Override
    public void visit(Termp termp) {

        int exponent = 0;
        int base = 0;

        if (termp.getStato().size() == 1) {

            termp.getStato().get(0).accept(this);
        } else {

            Iterator<Component> it = termp.getStato().iterator();
            Component temp = it.next();

            temp.accept(this);

            base = num;

            while (it.hasNext()) {

                Component temp1 = it.next();

                temp1.accept(this);

                if (exponent == 0) {

                    exponent = num;
                } else {

                    exponent *= num;
                }
            }

            num = (int) Math.pow(base, exponent);
        }
    }

    @Override
    public void visit(FactExpr factExpr) {

        factExpr.getStato().accept(this);
    }

    @Override
    public void visit(FactId factId) {

        num = factId.getStato();
    }

    @Override
    public void visit(FactNum factNum) {

        num = factNum.getStato();
    }

    public boolean getResult() {

        return bool;
    }
}